package org.grayrabbit.cms.plugin.servlet;

import java.io.IOException;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.grayrabbit.cms.plugin.ModuleDescriptor;
import org.grayrabbit.cms.plugin.Plugin;
import org.grayrabbit.cms.plugin.PluginAccessor;
import org.grayrabbit.cms.plugin.elements.ResourceLocation;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;



/**
 * @author sys53
 * @version 1.0
 * @created 06-一月-2012 17:14:55
 */
public class PluginResourceDownload implements DownloadStrategy {
	private static Logger log = LoggerFactory.getLogger(PluginResourceDownload.class);
	public ResourceUrlParser resourceUrlParser;
	private static final String DOWNLOAD_RESOURCE = "download";
	private final ResourceUrlParser urlParser = new ResourceUrlParser("resources");
	private PluginAccessor pluginAccessor;

	public void setPluginAccessor(PluginAccessor pluginAccessor) {
		this.pluginAccessor = pluginAccessor;
	}

	public PluginResourceDownload(PluginAccessor pluginAccessor)
	  {
	    this.pluginAccessor = pluginAccessor;
	  }
	
	public PluginResourceDownload() {

	}

	public void serveFile(BaseFileServerServlet servlet,HttpServletRequest request, HttpServletResponse response) throws IOException {
		String requestUri = servlet.urlDecode(request.getRequestURI());
	    PluginResource resource = this.urlParser.parse(requestUri);
	    if (resource != null)
	    {
	      servePluginResource(servlet, request, response, resource.getModuleCompleteKey(), resource.getResourceName());
	    }
	    else
	    {
	      log.info("Invalid resource path spec: " + request.getRequestURI());
	      response.sendError(404);
	    }
	}

	private void servePluginResource(BaseFileServerServlet servlet, HttpServletRequest request, HttpServletResponse response,String moduleCompleteKey, String resourceName) throws IOException {
		DownloadableResource resource = null;
	    if (moduleCompleteKey.indexOf(":") > -1)
	    {
	      ModuleDescriptor moduleDescriptor = this.pluginAccessor.getPluginModule(moduleCompleteKey);
	      if ((moduleDescriptor != null) && (this.pluginAccessor.isPluginModuleEnabled(moduleCompleteKey)))
	      {
	        resource = getResourceFromModule(moduleDescriptor, resourceName, servlet);
	      }
	      else
	      {
	        log.info("Module not found: " + moduleCompleteKey);
	        response.sendError(404);
	      }
	    }
	    else
	    {
	      Plugin plugin = this.pluginAccessor.getPlugin(moduleCompleteKey);
	      resource = getResourceFromPlugin(plugin, resourceName, "", servlet);
	    }
	    if (resource == null)
	    {
	      resource = getResourceFromPlugin(moduleCompleteKey, resourceName, servlet);
	    }
	    if (resource != null)
	    {
	      resource.serveResource(request,response);
	    }
	    else
	    {
	      log.info("Unable to find resource for plugin: " + moduleCompleteKey + " and path: " + resourceName);
	    }
	  }

	  private DownloadableResource getResourceFromPlugin(Plugin plugin,String resourcePath, String filePath, BaseFileServerServlet servlet) {
		  ResourceLocation resourceLocation = plugin.getResourceLocation("download", resourcePath);
		    if (resourceLocation != null)
		    {
		      return getDownloadablePluginResource(servlet, plugin, resourceLocation, filePath);
		    }
		    String[] nextParts = splitLastPathPart(resourcePath);
		    if (nextParts == null)
		    {
		      return null;
		    }
		    return getResourceFromPlugin(plugin, nextParts[0], nextParts[1] + filePath, servlet);
	}

	private DownloadableResource getResourceFromModule(ModuleDescriptor moduleDescriptor, String filePath,BaseFileServerServlet servlet) {
		return getResourceFromModule(moduleDescriptor, filePath, "", servlet);
	}

	private DownloadableResource getResourceFromModule(ModuleDescriptor moduleDescriptor, String resourcePath, String filePath,
			BaseFileServerServlet servlet) {
		Plugin plugin = this.pluginAccessor.getPlugin(moduleDescriptor.getPluginKey());
	    ResourceLocation resourceLocation = moduleDescriptor.getResourceLocation(DOWNLOAD_RESOURCE, resourcePath);
	    if (resourceLocation != null)
	    {
	      return getDownloadablePluginResource(servlet, plugin, resourceLocation, filePath);
	    }
	    String[] nextParts = splitLastPathPart(resourcePath);
	    if (nextParts == null)
	    {
	      return null;
	    }
	    return getResourceFromModule(moduleDescriptor, nextParts[0], nextParts[1] + filePath, servlet);
	}

	private String[] splitLastPathPart(String resourcePath) {
		int indexOfSlash = resourcePath.lastIndexOf('/');
	    if (resourcePath.endsWith("/"))
	    {
	      indexOfSlash = resourcePath.lastIndexOf('/', indexOfSlash - 1);
	    }
	    if (indexOfSlash < 0) return null;
	    return new String[] { resourcePath.substring(0, indexOfSlash + 1), resourcePath.substring(indexOfSlash + 1) };
	}

	private DownloadableResource getDownloadablePluginResource(
			BaseFileServerServlet servlet, Plugin plugin,
			ResourceLocation resourceLocation, String filePath) {
		if ("webContext".equalsIgnoreCase(resourceLocation.getParameter("source")))
	    {
	      return new DownloadableWebResource(servlet, plugin, resourceLocation, filePath);
	    }
	    return new DownloadableClasspathResource(servlet, plugin, resourceLocation, filePath);
	}

	private DownloadableResource getResourceFromPlugin(String moduleKey, String resourcePath, BaseFileServerServlet servlet)
	  {
	    if ((moduleKey.indexOf(':') < 0) || (moduleKey.indexOf(':') == moduleKey.length() - 1))
	    {
	      return null;
	    }

	    Plugin plugin = this.pluginAccessor.getPlugin(moduleKey.substring(0, moduleKey.indexOf(':')));
	    if (plugin == null)
	    {
	      return null;
	    }

	    return getResourceFromPlugin(plugin, resourcePath, "", servlet);
	}

	public boolean matches(String urlPath) {
		return this.urlParser.matches(urlPath);
	}

}